import * as THREE from '../../build/three.module.js';
import Stats from '../../jsm/libs/stats.module.js'

import { GUI } from '../../jsm/libs/dat.gui.module.js'
import { OBJLoader } from '../../jsm/loaders/OBJLoader.js';
import { OrbitControls } from '../../jsm/controls/OrbitControls.js'

const settings = {
  metalness: 1.0,
  roughness: 0.4,
  ambientIntensity: 0.2,
  aoMapIntensity: 1.0,
  envMapIntensity: 1.0,
  displacementScale: 2.436143, // from original model
  normalScale: 1.0
};

// 场景
const scene = new THREE.Scene();

// 相机
const aspect = innerWidth / innerHeight;
const height = 500;
const camera = new THREE.OrthographicCamera(-aspect * height, aspect * height, height, -height, 1, 10000);
camera.position.z = 1500;
scene.add(camera);

// 渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio(devicePixelRatio);
renderer.setSize(innerWidth, innerHeight);
renderer.gammaInput = true;
renderer.gammaOutput = true;
document.body.appendChild(renderer.domElement);

// 控制器
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableZoom = false;
controls.enableDamping = true;

// 光照
const abl = new THREE.AmbientLight(0xffffff, settings.ambientIntensity);
scene.add(abl);

const pl1 = new THREE.PointLight(0xff0000, 0.5);
pl1.position.z = 2500;
scene.add(pl1);

const pl2 = new THREE.PointLight(0xff6666, 1);
camera.add(pl2);

const pl3 = new THREE.PointLight(0x0000ff, 0.5);
pl3.position.x = - 1000;
pl3.position.z = 1000;
scene.add(pl3);

// 环境贴图
const path = '../../textures/cube/SwedishRoyalCastle/';
const ext = '.jpg';
const urls = [
  path + 'px' + ext, path + 'nx' + ext,
  path + 'py' + ext, path + 'ny' + ext,
  path + 'pz' + ext, path + 'nz' + ext
]
const reflectionCube = new THREE.CubeTextureLoader().load(urls);

// 贴图
const textureLoader = new THREE.TextureLoader();
const normalMap = textureLoader.load('../../models/obj/ninja/normal.jpg');
const aoMap = textureLoader.load('../../models/obj/ninja/ao.jpg');
const displacementMap = textureLoader.load('../../models/obj/ninja/displacement.jpg');

// 材质
const mtl = new THREE.MeshStandardMaterial({

  color: 0x888888,
  roughness: settings.roughness,
  metalness: settings.metalness,

  normalMap: aoMap,
  normalScale: new THREE.Vector2(1, -1),

  aoMap: aoMap,
  aoMapIntensity: settings.aoMapIntensity,

  displacementMap: displacementMap,
  displacementScale: settings.displacementScale,
  displacementBias: -0.428408,

  envMap: reflectionCube,
  envMapIntensity: settings.envMapIntensity,

  side: THREE.DoubleSide

})

// 几何体模型
const loader = new OBJLoader();
let mesh;
loader.load('../../models/obj/ninja/ninjaHead_Low.obj', group => {
  const geo = group.children[0].geometry;
  geo.attributes.uv2 =  geo.attributes.uv;
  geo.center();

  mesh = new THREE.Mesh(geo, mtl);
  mesh.scale.multiplyScalar(25);
  scene.add(mesh);
})

// 统计
const stats = new Stats();
document.body.appendChild(stats.dom);

// GUI
const gui = new GUI();
gui.add(settings, 'metalness').min(0).max(1).onChange(val => mtl.metalness = val);
gui.add(settings, 'roughness').min(0).max(1).onChange(val => mtl.roughness = val);
gui.add(settings, 'aoMapIntensity').min(0).max(1).onChange(val => mtl.aoMapIntensity = val);
gui.add(settings, 'ambientIntensity').min(0).max(1).onChange(val => mtl.ambientIntensity = val);
gui.add(settings, 'envMapIntensity').min(0).max(1).onChange(val => mtl.envMapIntensity = val);
gui.add(settings, 'displacementScale').min(0).max(3.0).onChange(val => mtl.displacementScale = val);
gui.add(settings, 'normalScale').min(-1).max(1).onChange(val => mtl.normalScale.set(1, -1).multiplyScalar(val));

// 事件监听
const handleWindowResize = () => {
  const aspect = innerWidth / innerHeight;
  camera.left = -height * aspect;
  camera.right = height * aspect;
  camera.top = height;
  camera.bottom = -height;

  camera.updateProjectionMatrix();

  renderer.setSize(innerWidth, innerHeight);
}
window.addEventListener('resize', handleWindowResize);

// 渲染函数
let r = 0.0; // 自由光源移动半径
const render = () => {
  pl1.position.x = 2500 * Math.cos(r);
  pl1.position.z = 2500 * Math.sin(r);

  r += 0.01;

  renderer.render(scene, camera);
}

// 驱动函数
const animate = () => {
  requestAnimationFrame(animate);

  stats.update();
  render();
}
animate();